package com.pokermind.dse.tcp.protocol;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

import static com.pokermind.dse.tcp.protocol.ProtocolConstants.*;

/**
 * TCP Protocol Decoder - JSON Version
 * 高性能JSON协议解码器，支持粘包/半包处理
 * 
 * Protocol Format:
 * +----------+----------+------------------+
 * | Protocol | Body     | JSON String      |
 * | ID       | Length   |                  |
 * | (2 bytes)| (4 bytes)| (N bytes UTF-8)  |
 * +----------+----------+------------------+
 * 
 * 性能优化要点:
 * 1. 最小化内存拷贝，使用ByteBuf slice
 * 2. 提前验证协议头，避免无效解析
 * 3. JSON解析错误快速失败
 * 4. 详细的错误处理和监控
 * 
 * @author PokerMind Team
 */
public class ProtocolDecoder extends ByteToMessageDecoder {

    private static final Logger logger = LoggerFactory.getLogger(ProtocolDecoder.class);

    // Jackson ObjectMapper for JSON parsing
    private final ObjectMapper objectMapper;

    public ProtocolDecoder() {
        this.objectMapper = new ObjectMapper();
        // 配置ObjectMapper以提高性能
        this.objectMapper.configure(com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_COMMENTS, false);
        this.objectMapper.configure(com.fasterxml.jackson.core.JsonParser.Feature.ALLOW_YAML_COMMENTS, false);
    }

    public ProtocolDecoder(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        // 检查是否有足够的数据读取协议头
        while (in.readableBytes() >= HEADER_SIZE) {
            
            // 标记当前读取位置，以便回滚
            in.markReaderIndex();
            
            try {
                // 读取协议头
                short protocolId = in.readShort();
                int bodyLength = in.readInt();
                
                // 验证协议头
                if (!isValidHeader(protocolId, bodyLength)) {
                    logger.warn("Invalid protocol header: protocolId={}, bodyLength={}, from={}",
                            protocolId, bodyLength, ctx.channel().remoteAddress());
                    ctx.close(); // 关闭无效连接
                    return;
                }
                
                // 检查消息体是否完整接收
                if (in.readableBytes() < bodyLength) {
                    // 半包，回滚读取位置，等待更多数据
                    in.resetReaderIndex();
                    return;
                }
                
                // 读取消息体 (JSON字符串)
                String jsonBody = in.readCharSequence(bodyLength, CharsetUtil.UTF_8).toString();
                
                // 解析并验证JSON
                JsonNode jsonNode = parseAndValidateJson(jsonBody);
                if (jsonNode == null) {
                    // V4.9: 增强错误日志 - 提取 rqid
                    String rqid = extractRqidFromJson(jsonBody);
                    logger.warn("Failed to parse JSON message: protocolId={}, rqid={}, bodyLength={}, bodyPreview={}", 
                            protocolId, 
                            rqid != null ? rqid : "unknown",
                            bodyLength, 
                            jsonBody.length() > 100 ? jsonBody.substring(0, 100) + "..." : jsonBody);
                    
                    // V4.9: 返回错误响应给客户端（避免客户端超时等待）
                    sendErrorResponse(ctx, protocolId, rqid, "JSON parsing failed: invalid format");
                    continue; // 跳过这个消息，继续处理下一个
                }
                
                // 创建协议消息对象
                ProtocolMessage protocolMessage = ProtocolMessage.createRequest(protocolId, jsonBody, jsonNode, ctx.channel());
                protocolMessage.markProcessStart();
                
                out.add(protocolMessage);
                
                if (logger.isDebugEnabled()) {
                    logger.debug("Decoded message: {}", protocolMessage);
                }
                
            } catch (Exception e) {
                logger.error("Error decoding protocol message from {}: {}", 
                        ctx.channel().remoteAddress(), e.getMessage(), e);
                in.resetReaderIndex();
                ctx.close(); // 关闭有问题的连接
                return;
            }
        }
    }

    /**
     * 验证协议头是否有效
     */
    private boolean isValidHeader(short protocolId, int bodyLength) {
        // 检查协议ID是否有效
        if (!isValidProtocol(protocolId)) {
            return false;
        }
        
        // 检查消息体长度是否合理
        if (bodyLength < 0 || bodyLength > MAX_BODY_SIZE) {
            return false;
        }
        
        // JSON消息体至少应该有2个字符: {}
        if (bodyLength < 2) {
            return false;
        }
        
        return true;
    }

    /**
     * 解析并验证JSON格式
     */
    private JsonNode parseAndValidateJson(String jsonBody) {
        try {
            // 基本格式检查
            if (jsonBody == null || jsonBody.trim().isEmpty()) {
                return null;
            }
            
            // 快速检查JSON格式
            String trimmed = jsonBody.trim();
            if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
                logger.warn("Invalid JSON format: expected object, got: {}", 
                        trimmed.length() > 50 ? trimmed.substring(0, 50) + "..." : trimmed);
                return null;
            }
            
            // 解析JSON
            JsonNode jsonNode = objectMapper.readTree(jsonBody);
            
            // 验证是否为有效的对象节点
            if (!jsonNode.isObject()) {
                logger.warn("JSON is not an object: {}", jsonNode.getNodeType());
                return null;
            }
            
            return jsonNode;
            
        } catch (Exception e) {
            // V4.9: JSON 解析失败 - ERROR 级别 + 异常堆栈
            String rqid = extractRqidFromJson(jsonBody);
            
            // 提取错误位置
            String errorPosition = "";
            if (e.getMessage() != null && e.getMessage().contains("column:")) {
                try {
                    String columnStr = e.getMessage().substring(e.getMessage().indexOf("column:") + 7).trim();
                    int column = Integer.parseInt(columnStr.split("[^0-9]")[0]);
                    if (column > 0 && column <= jsonBody.length()) {
                        int start = Math.max(0, column - 30);
                        int end = Math.min(jsonBody.length(), column + 30);
                        errorPosition = ", errorNear=" + jsonBody.substring(start, end).replace("\n", "");
                    }
                } catch (Exception ex) {
                    // 忽略
                }
            }
            
            // 一行记录关键信息 + 打印异常堆栈
            logger.error("JSON parsing failed: rqid={}, length={}, error={}{}, body={}", 
                    rqid != null ? rqid : "unknown",
                    jsonBody.length(),
                    e.getMessage() != null && e.getMessage().length() > 100 ? 
                        e.getMessage().substring(0, 100) : e.getMessage(),
                    errorPosition,
                    jsonBody.length() <= 500 ? jsonBody : 
                        jsonBody.substring(0, 250) + "..." + jsonBody.substring(jsonBody.length() - 100),
                    e);  // 打印异常堆栈
            
            return null;
        }
    }
    
    /**
     * 从 JSON 字符串中提取 rqid（用于错误日志）
     */
    private String extractRqidFromJson(String jsonBody) {
        try {
            // 简单的字符串匹配提取 rqid
            int rqidIndex = jsonBody.indexOf("\"rqid\"");
            if (rqidIndex > 0) {
                int colonIndex = jsonBody.indexOf(":", rqidIndex);
                int startQuote = jsonBody.indexOf("\"", colonIndex + 1);
                int endQuote = jsonBody.indexOf("\"", startQuote + 1);
                if (startQuote > 0 && endQuote > startQuote) {
                    return jsonBody.substring(startQuote + 1, endQuote);
                }
            }
        } catch (Exception e) {
            // 忽略提取失败
        }
        return null;
    }
    
    /**
     * V4.9: 发送错误响应给客户端（JSON 解析失败时）
     */
    private void sendErrorResponse(ChannelHandlerContext ctx, short requestProtocolId, String rqid, String errorMessage) {
        try {
            // 构造错误响应 JSON
            String errorJson = String.format(
                "{\"success\":false,\"rqid\":\"%s\",\"error\":\"%s\",\"error_code\":\"INVALID_JSON\"}",
                rqid != null ? rqid : "unknown",
                errorMessage
            );
            
            // 响应协议 ID = 请求协议 ID + 1（遵循协议约定）
            short responseProtocolId = (short)(requestProtocolId + 1);
            
            // 编码并发送响应
            io.netty.buffer.ByteBuf response = ctx.alloc().buffer();
            response.writeShort(responseProtocolId);
            response.writeInt(errorJson.length());
            response.writeCharSequence(errorJson, CharsetUtil.UTF_8);
            
            ctx.writeAndFlush(response);
            
            logger.debug("Sent error response: protocolId={}, rqid={}, error={}", 
                responseProtocolId, rqid, errorMessage);
            
        } catch (Exception e) {
            logger.error("Failed to send error response: {}", e.getMessage(), e);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("Protocol decoder error from {}: {}", 
                ctx.channel().remoteAddress(), cause.getMessage(), cause);
        ctx.close();
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        if (logger.isDebugEnabled()) {
            logger.debug("Channel inactive: {}", ctx.channel().remoteAddress());
        }
        super.channelInactive(ctx);
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        if (logger.isDebugEnabled()) {
            logger.debug("Protocol decoder added to channel: {}", ctx.channel().remoteAddress());
        }
        super.handlerAdded(ctx);
    }

}
